package com.darcye.clear.work;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.jdom2.Attribute;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.XMLOutputter;

import com.darcye.clear.utils.DeleteLogger;
import com.darcye.clear.utils.FileList;
import com.darcye.clear.utils.FileUtils;

public abstract class BaseWorker  implements WorkInterface{
	
	private static String mProjectPath;
	
	private static List<File> mJavaFiles;
	
	private static String[] mDiffLayoutPaths;
	private static String[] mDiffDrawablePaths;
	
	private static HashSet<String> mIgnoreDeleteFiles; 
	
	private static boolean mIsBackup = false;
	
	private static final String RES_SUFFIX = ".xml";
	
	private static String mBackuPath;
	
	private DeleteLogger mLogger;
	
	/**
	 * 可能出现的资源Id
	 */
	protected final Set<String> mUsedArrayIdSet = new LinkedHashSet<String>();
	protected final Set<String> mUsedLayoutIdSet = new LinkedHashSet<String>();
	protected final Set<String> mUsedStyleIdSet = new LinkedHashSet<String>();
	protected final Set<String> mUsedMenuIdSet = new LinkedHashSet<String>();
	protected final Set<String> mUsedAnimIdSet = new LinkedHashSet<String>();
	protected final Set<String> mUsedAnimatorIdSet = new LinkedHashSet<String>();
	protected final Set<String> mUsedTransitionIdSet = new LinkedHashSet<String>();
	protected final Set<String> mUsedDrawableIdSet = new LinkedHashSet<String>();
	protected final Set<String> mUsedColorIdSet = new LinkedHashSet<String>();
	protected final Set<String> mUsedStringIdSet = new LinkedHashSet<String>();
	protected final Set<String> mUsedIntegerIdSet = new LinkedHashSet<String>();
	protected final Set<String> mUsedBoolIdSet = new LinkedHashSet<String>();
	protected final Set<String> mUsedDimenIdSet = new LinkedHashSet<String>();
	protected final Set<String> mUsedAttrIdSet = new LinkedHashSet<String>();
	protected final Set<String> mUsedStyleableIdSet = new LinkedHashSet<String>();
	protected final Set<String> mUsedIdIdSet = new LinkedHashSet<String>();
	
	public Set<String> getUsedLayoutIdSet() {
		return mUsedLayoutIdSet;
	}

	public Set<String> getUsedStyleIdSet() {
		return mUsedStyleIdSet;
	}

	public Set<String> getUsedMenuIdSet() {
		return mUsedMenuIdSet;
	}

	public Set<String> getUsedAnimIdSet() {
		return mUsedAnimIdSet;
	}
	
	public Set<String> getUsedAnimatorIdSet() {
		return mUsedAnimatorIdSet;
	}

	public Set<String> getUsedTransitionIdSet() {
		return mUsedTransitionIdSet;
	}

	public Set<String> getUsedDrawableIdSet() {
		return mUsedDrawableIdSet;
	}

	public Set<String> getUsedColorIdSet() {
		return mUsedColorIdSet;
	}

	public Set<String> getUsedStringIdSet() {
		return mUsedStringIdSet;
	}
	
	public Set<String> getUsedIntegerIdSet() {
		return mUsedIntegerIdSet;
	}

	public Set<String> getUsedBoolIdSet() {
		return mUsedBoolIdSet;
	}

	public Set<String> getUsedDimenIdSet(){
		return mUsedDimenIdSet;
	}
	
	public Set<String> getUsedArrayIdSet() {
		return mUsedArrayIdSet;
	}

	public Set<String> getUsedAttrIdSet() {
		return mUsedAttrIdSet;
	}

	public Set<String> getUsedStyleableIdSet() {
		return mUsedStyleableIdSet;
	}
	
	public Set<String> getUsedIdIdSet() {
		return mUsedIdIdSet;
	}

	protected void setLogger(DeleteLogger logger){
		this.mLogger = logger;
	}
	
	private FilenameFilter mJavaFileFilter = new FilenameFilter() {
		public boolean accept(File dir, String name) {
			return name.endsWith(".java");
		}
	};
	
	public static String getBackuPath() {
		return mBackuPath;
	}
	
	private static void setBackuPath(String mBackuPath) {
		BaseWorker.mBackuPath = mBackuPath;
	}

	/**
	 * 设置项目目录
	 * @param projectPath
	 */
	private static void setProjectPath(String projectPath){
		if(projectPath.endsWith("/"))
			projectPath = projectPath.substring(0, projectPath.length()-1);
		mProjectPath = projectPath;
	}
	
	/**
	 * 
	 * @param deleleFilePath
	 */
	private static void setConfigIgnorePaths(String configIgnoreFile){
		BufferedReader reader = null;
		try {
			File f = new File(configIgnoreFile);
			if(f.isFile() && f.exists()){
				mIgnoreDeleteFiles = new HashSet<String>();
				reader = new BufferedReader(new InputStreamReader(new FileInputStream(f)));
				String lineText;
				while((lineText = reader.readLine())!=null){
					lineText = lineText.trim();
					if(lineText.isEmpty() || lineText.startsWith("#")){
						continue;
					}
					lineText = lineText.replace("\\", "/");
					mIgnoreDeleteFiles.add(lineText);
				}
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally{
			if(reader!=null)
				try {
					reader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
	}
	
	/**
	 * 
	 *  @param projectPath 项目目录
	 *  @param configIgnoreFile 配置忽略删除文件目录
	 */
	public static void initPath(String projectPath,String configIgnoreFile,String backupPath){
		setProjectPath(projectPath);
		setConfigIgnorePaths(configIgnoreFile);
		setBackuPath(backupPath);
	}
	
	/**
	 * 获取所有Java文件
	 * @return
	 */
	protected List<File> getAllJavaFiles(){
		if(mJavaFiles == null){
			FileList fl = new FileList(getJavaSrcPath());
			mJavaFiles=  fl.recurseListFiles(mJavaFileFilter);
		}
		return mJavaFiles;
	}
	
	/**
	 * 根据layout id 获取不同规格的layout文件
	 * @param layoutId
	 * @return
	 */
	protected List<File> getDiffLayoutFiles(String layoutId){
		String layoutFileName = getResFileName(layoutId);
		String[] diffLayoutPaths = getDiffLayoutPath();
		List<File> diffLayouts = new ArrayList<File>(diffLayoutPaths.length);
		File f;
		for (String p : diffLayoutPaths) {
			f = new File(p+"/"+layoutFileName);
			if(f.exists()&&f.isFile())
				diffLayouts.add(f);
		}
		return diffLayouts;
	}
	
	protected String getResFileName(String resId){
		return resId + RES_SUFFIX;
	}
	
	protected String getJavaSrcPath(){
		checkProjectPath();
		return mProjectPath + "/src";
	}
	
	public static String getResourcePath(){
		checkProjectPath();
		return mProjectPath+ "/res";
	}
	
	protected String getManifestPath(){
		return mProjectPath+"/AndroidManifest.xml";
	}
	
	
	protected String[] getDiffLayoutPath(){
		if(mDiffLayoutPaths == null){
			File layoutPath = new File(getResourcePath());
			File[] paths = layoutPath.listFiles(new FilenameFilter() {
				public boolean accept(File dir, String name) {
					return dir.isDirectory()&&name.startsWith("layout");
				}
			});
			mDiffLayoutPaths = new String[paths.length];
			for(int i=0; i<paths.length; ++i){
				mDiffLayoutPaths[i] = paths[i].getPath();
			}
		}
		return mDiffLayoutPaths;
	}
	
	protected String[] getDiffDrawablePath(){
		if(mDiffDrawablePaths == null){
			File layoutPath = new File(getResourcePath());
			File[] paths = layoutPath.listFiles(new FilenameFilter() {
				public boolean accept(File dir, String name) {
					return dir.isDirectory()&&name.startsWith("drawable");
				}
			});
			mDiffDrawablePaths = new String[paths.length];
			for(int i=0; i<paths.length; ++i){
				mDiffDrawablePaths[i] = paths[i].getPath();
			}
		}
		return mDiffDrawablePaths;
	}
	
	private static void checkProjectPath(){
		if(mProjectPath == null && new File(mProjectPath).exists())
			throw new NullPointerException("project path must be not empty.");
	}
	
	/**
	 * 清理没有包含关系的独立资源(如color/integer/string/dimen...)
	 * 
	 * @param filenameFliter
	 * @param resIdSet
	 */
	protected void executeForTerminalId(FilenameFilter filenameFliter,String tagName,Set<String> resIdSet){
		Element rootEl;
		List<Element> resEls;
		List<Element> cloneResEls;
		String resName;
		Document mDocument;
		Attribute typeAttr;
		FileList fl = new FileList(getResourcePath());
		List<File> resFiles = fl.recurseListFiles(filenameFliter);
		for (File resFile : resFiles) {
			if(isIgnoreDeleteFile(resFile))
				continue;
			
			SAXBuilder builder = new SAXBuilder();
			boolean isFileChange = false;
			try {
				mDocument = builder.build(resFile);
				rootEl = mDocument.getRootElement();
				
				resEls = rootEl.getChildren(tagName);
				//tagName = resType
				if(resEls !=null && !resEls.isEmpty()){
					cloneResEls = new ArrayList<Element>(resEls);
					for (Element resEl : cloneResEls) {
						resName = resEl.getAttribute("name").getValue();
						if(!resIdSet.contains(resName)){
							isFileChange = true;
							if(mLogger !=null)
								mLogger.log(resName,resFile.getPath());
							rootEl.removeContent(resEl);
						}
					}
				}
				
				//type = resType 
				resEls = rootEl.getChildren("item");
				if(resEls !=null && !resEls.isEmpty()){
					cloneResEls = new ArrayList<Element>(resEls);
					for (Element resEl : cloneResEls) {
						typeAttr = resEl.getAttribute("type");
						if(typeAttr!=null && typeAttr.getValue().equals(tagName)){
							resName = resEl.getAttribute("name").getValue();
							if(!resIdSet.contains(resName)){
								isFileChange = true;
								if(mLogger !=null)
									mLogger.log(resName,resFile.getPath());
								rootEl.removeContent(resEl);
							}
						}
					}
				}
				
				if(isFileChange){
					backupDelFile(resFile);
					writeBack(resFile, mDocument);
				}
			} catch (JDOMException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		if(mLogger !=null)
			mLogger.finish();
	}
	
	/**
	 * 回写
	 * @param styleFile
	 * @param doc
	 */
	protected void writeBack(File styleFile,Document doc){
		XMLOutputter outp = new XMLOutputter();
		FileOutputStream fileOutput = null;
		try {
			fileOutput = new FileOutputStream(styleFile);
			outp.output(doc, fileOutput);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			if(fileOutput!=null)
				try {
					fileOutput.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
	}
	
	/**
	 * 是否要忽略删除的文件
	 * @param f
	 */
	protected boolean isIgnoreDeleteFile(File f){
		String resFolder = f.getParentFile().getName();
		String resName = f.getName();
		String relativePath = resFolder + "/" + resName;
		for(String ignoreFile : mIgnoreDeleteFiles){
			if(relativePath.matches(ignoreFile)){
				return true;
			}
		}
		return false;
	}
	
	/**
	 * 备份删除文件
	 * @param delFile
	 */
	protected void backupDelFile(File delFile){
		if(!mIsBackup){
			//首次备份先清除以前的备份文件
			FileUtils.deleteDirectory(mBackuPath);
		}
		String resType = delFile.getParentFile().getName();
		String destPath = mBackuPath +File.separator+"res/" + resType;
		FileUtils.copyFile(delFile, destPath);
		mIsBackup = true;
	}
	
}
